package abg.core.common.util;

import abg.core.domain.sys.FileConfig;
import abg.core.domain.sys.MSG;
import abg.core.domain.sys.ServiceException;
import io.minio.*;
import io.minio.messages.DeleteObject;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.FileInputStream;
import java.io.FilterInputStream;
import java.io.InputStream;
import java.util.List;
import java.util.stream.Collectors;


/**
 * MINIO文件操作
 */
@Slf4j
@Component
public class MinioKit {

    @Resource
    private FileConfig fileConfig;

    /**
     * 桶占位符
     */
    private static final String BUCKET_PARAM = "${bucket}";
    /**
     * bucket权限-只读
     */
    private static final String READ_ONLY = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetObject\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";
    /**
     * bucket权限-只读
     */
    private static final String WRITE_ONLY = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";
    /**
     * bucket权限-读写
     */
    private static final String READ_WRITE = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";


    private MinioClient minioClient;

    private MinioClient minioIntranetClient;

    public String uploadGetURI(InputStream inputStream, String fileName, String contentType) {
        String bucket = fileConfig.minioBucketName();
        try {
            int available = inputStream.available();
            MinioClient client = getOssClient();
            PutObjectArgs putObjectArgs =
                    PutObjectArgs.builder()
                            .bucket(bucket)
                            .stream(inputStream, inputStream.available(), -1)
                            .object(fileName)
                            .contentType(contentType)
                            .build();
            client.putObject(putObjectArgs);
        } catch (Exception e) {
            throw new ServiceException(MSG.FILE_UPLOAD_ER, StringKit.getExceptionMsg(e));
        }
        //拼接出可访问的url地址
        return "/" + bucket + "/" + fileName;
    }

    public String uploadGetURI(String localFilePath, String name, String contentType) {
        try {
            return this.uploadGetURI(new FileInputStream(localFilePath), name, contentType);
        } catch (Exception e) {
            throw new ServiceException(MSG.FILE_UPLOAD_ER, e.getMessage());
        }
    }


    public String uploadGetURIIntranet(InputStream inputStream, String fileName, String contentType) {
        String bucket = fileConfig.minioBucketName();
        try {
            MinioClient client = getIntranetOssClient();
            PutObjectArgs putObjectArgs =
                    PutObjectArgs.builder()
                            .bucket(bucket)
                            .stream(inputStream, inputStream.available(), -1)
                            .object(fileName)
                            .contentType(contentType)
                            .build();
            client.putObject(putObjectArgs);
        } catch (Exception e) {
            throw new ServiceException(MSG.FILE_UPLOAD_ER, e.getMessage());
        }
        //拼接出可访问的url地址
        return "/" + bucket + "/" + fileName;
    }

    public String uploadGetURIIntranet(String localFilePath, String name, String contentType) {
        try {
            return this.uploadGetURIIntranet(new FileInputStream(localFilePath), name, contentType);
        } catch (Exception e) {
            throw new ServiceException(MSG.FILE_UPLOAD_ER, e.getMessage());
        }
    }


    public void deleteFile(List<String> nameList) {
        if (nameList == null || nameList.isEmpty()) {
            return;
        }
        MinioClient ossClient = getOssClient();
        List<DeleteObject> objectList = nameList.stream().map(DeleteObject::new).collect(Collectors.toList());
        ossClient.removeObjects(RemoveObjectsArgs.builder().objects(objectList).bucket(fileConfig.minioBucketName()).build());
    }


    /**
     * 获取oss client
     */
    private MinioClient getOssClient() {
        MinioClient minioClient;
        try {
            minioClient = MinioClient.builder()
                    .endpoint(fileConfig.minioEndpoint())
                    .credentials(fileConfig.minioAccessKey(), fileConfig.minioSecretKey())
                    .build();
            //查看对应的bucket是否已经存在，不存在则创建
            if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(fileConfig.minioBucketName()).build())) {
                //创建bucket
                MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket(fileConfig.minioBucketName()).build();
                minioClient.makeBucket(makeBucketArgs);
                setBucketPolicy(minioClient, fileConfig.minioBucketName(), "read-write");
                //log.info("创建minio桶成功{}", fileConfig.getM_bucketName());
            }
        } catch (Exception e) {
            e.printStackTrace();
            //晴空配置
            minioClient = null;
            throw new ServiceException(MSG.FILE_DELETE_ERROR, e.getMessage());
        }


        return minioClient;
    }

    /**
     * 获取 内网 oss client
     */
    private MinioClient getIntranetOssClient() {
        MinioClient minioIntranetClient;
        try {
            //创建客户端
            minioIntranetClient = MinioClient.builder()
                    .endpoint(fileConfig.minioIntranetEndpoint())
                    .credentials(fileConfig.minioAccessKey(), fileConfig.minioSecretKey())
                    .build();

            //查看对应的bucket是否已经存在，不存在则创建
            if (!minioIntranetClient.bucketExists(BucketExistsArgs.builder().bucket(fileConfig.minioBucketName()).build())) {
                //创建bucket
                MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket(fileConfig.minioBucketName()).build();
                minioIntranetClient.makeBucket(makeBucketArgs);
                setBucketPolicy(minioIntranetClient, fileConfig.minioBucketName(), "read-write");
                //log.info("创建minio桶成功{}", fileConfig.getM_bucketName());
            }
        } catch (Exception e) {
            //晴空配置
            minioIntranetClient = null;
            throw new ServiceException(MSG.FILE_DELETE_ERROR, e.getMessage());
        }
        return minioIntranetClient;
    }


    /**
     * 更新桶权限策略
     *
     * @param bucket 桶
     * @param policy 权限
     */
    public static void setBucketPolicy(MinioClient client, String bucket, String policy) throws Exception {
        switch (policy) {
            case "read-only":
                client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).config(READ_ONLY.replace(BUCKET_PARAM, bucket)).build());
                break;
            case "write-only":
                client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).config(WRITE_ONLY.replace(BUCKET_PARAM, bucket)).build());
                break;
            case "read-write":
                client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).region("public").config(READ_WRITE.replace(BUCKET_PARAM, bucket)).build());
                break;
            case "none":
            default:
                break;
        }
    }

    /**
     * 从MinIO获取文件的流
     *
     * @param filePath MinIO上的文件路径 jldz/test.doc 带后缀名
     */
    public FilterInputStream getFileStream(String filePath) throws Exception {
        GetObjectArgs getObjectArgs = GetObjectArgs
                .builder()
                .bucket(fileConfig.minioBucketName())
                .object(filePath)
                .build();
        return getOssClient().getObject(getObjectArgs);
    }

    /**
     * 从MinIO获取文件的流
     *
     * @param filePath MinIO上的文件路径 jldz/test.doc 带后缀名
     */
    public FilterInputStream getFileStreamIntranet(String filePath) throws Exception {
        GetObjectArgs getObjectArgs = GetObjectArgs
                .builder()
                .bucket(fileConfig.minioBucketName())
                .object(filePath)
                .build();
        return getIntranetOssClient().getObject(getObjectArgs);
    }


}
